// Copyright Epic Games, Inc. All Rights Reserved.

#include "LyraSettingsShared.h"

#include "Framework/Application/SlateApplication.h"
#include "Internationalization/Culture.h"
#include "Kismet/GameplayStatics.h"
#include "Misc/App.h"
#include "Misc/ConfigCacheIni.h"
#include "Player/LyraLocalPlayer.h"
#include "Rendering/SlateRenderer.h"
#include "SubtitleDisplaySubsystem.h"
#include "EnhancedInputSubsystems.h"
#include "UserSettings/EnhancedInputUserSettings.h"

#include UE_INLINE_GENERATED_CPP_BY_NAME(LyraSettingsShared)

// 定义共享设置槽位名称
static FString SHARED_SETTINGS_SLOT_NAME = TEXT("SharedGameSettings");

// 控制台变量命名空间
namespace LyraSettingsSharedCVars
{
	static float DefaultGamepadLeftStickInnerDeadZone = 0.25f; // 默认游戏手柄左摇杆内死区
	static FAutoConsoleVariableRef CVarGamepadLeftStickInnerDeadZone(
		TEXT("gpad.DefaultLeftStickInnerDeadZone"),
		DefaultGamepadLeftStickInnerDeadZone,
		TEXT("Gamepad left stick inner deadzone") // 游戏手柄左摇杆内死区
	);

	static float DefaultGamepadRightStickInnerDeadZone = 0.25f; // 默认游戏手柄右摇杆内死区
	static FAutoConsoleVariableRef CVarGamepadRightStickInnerDeadZone(
		TEXT("gpad.DefaultRightStickInnerDeadZone"),
		DefaultGamepadRightStickInnerDeadZone,
		TEXT("Gamepad right stick inner deadzone") // 游戏手柄右摇杆内死区
	);	
}

/**
 * 构造函数
 */
ULyraSettingsShared::ULyraSettingsShared()
{
	// 注册文化更改回调
	FInternationalization::Get().OnCultureChanged().AddUObject(this, &ThisClass::OnCultureChanged);

	// 初始化游戏手柄死区默认值
	GamepadMoveStickDeadZone = LyraSettingsSharedCVars::DefaultGamepadLeftStickInnerDeadZone;
	GamepadLookStickDeadZone = LyraSettingsSharedCVars::DefaultGamepadRightStickInnerDeadZone;
}

/**
 * 获取最新数据版本
 * @return 数据版本号
 */
int32 ULyraSettingsShared::GetLatestDataVersion() const
{
	// 0 = 在子类化ULocalPlayerSaveGame之前
	// 1 = 第一个适当版本
	return 1;
}

/**
 * 创建临时设置
 * @param LocalPlayer 本地玩家对象
 * @return 共享设置实例
 */
ULyraSettingsShared* ULyraSettingsShared::CreateTemporarySettings(const ULyraLocalPlayer* LocalPlayer)
{
	// 这不是从磁盘加载的，但应该设置为保存
	ULyraSettingsShared* SharedSettings = Cast<ULyraSettingsShared>(CreateNewSaveGameForLocalPlayer(ULyraSettingsShared::StaticClass(), LocalPlayer, SHARED_SETTINGS_SLOT_NAME));

	SharedSettings->ApplySettings();

	return SharedSettings;
}

/**
 * 加载或创建设置
 * @param LocalPlayer 本地玩家对象
 * @return 共享设置实例
 */
ULyraSettingsShared* ULyraSettingsShared::LoadOrCreateSettings(const ULyraLocalPlayer* LocalPlayer)
{
	// 这将在加载时阻塞主线程
	ULyraSettingsShared* SharedSettings = Cast<ULyraSettingsShared>(LoadOrCreateSaveGameForLocalPlayer(ULyraSettingsShared::StaticClass(), LocalPlayer, SHARED_SETTINGS_SLOT_NAME));

	SharedSettings->ApplySettings();

	return SharedSettings;
}

/**
 * 异步加载或创建设置
 * @param LocalPlayer 本地玩家对象
 * @param Delegate 设置加载事件委托
 * @return 如果成功开始加载返回true，否则返回false
 */
bool ULyraSettingsShared::AsyncLoadOrCreateSettings(const ULyraLocalPlayer* LocalPlayer, FOnSettingsLoadedEvent Delegate)
{
	// 创建本地Lambda函数处理加载完成
	FOnLocalPlayerSaveGameLoadedNative Lambda = FOnLocalPlayerSaveGameLoadedNative::CreateLambda([Delegate]
		(ULocalPlayerSaveGame* LoadedSave)
		{
			ULyraSettingsShared* LoadedSettings = CastChecked<ULyraSettingsShared>(LoadedSave);
			
			LoadedSettings->ApplySettings();

			Delegate.ExecuteIfBound(LoadedSettings);
		});

	return ULocalPlayerSaveGame::AsyncLoadOrCreateSaveGameForLocalPlayer(ULyraSettingsShared::StaticClass(), LocalPlayer, SHARED_SETTINGS_SLOT_NAME, Lambda);
}

/**
 * 保存设置
 */
void ULyraSettingsShared::SaveSettings()
{
	// 安排异步保存，因为失败也没关系
	AsyncSaveGameToSlotForLocalPlayer();

	// TODO_BH: 将其移动到序列化函数中，并增加版本号
	if (UEnhancedInputLocalPlayerSubsystem* System = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(OwningPlayer))
	{
		if (UEnhancedInputUserSettings* InputSettings = System->GetUserSettings())
		{
			InputSettings->AsyncSaveSettings();
		}
	}
}

/**
 * 应用设置
 */
void ULyraSettingsShared::ApplySettings()
{
	ApplySubtitleOptions(); // 应用字幕选项
	ApplyBackgroundAudioSettings(); // 应用后台音频设置
	ApplyCultureSettings(); // 应用文化设置

	if (UEnhancedInputLocalPlayerSubsystem* System = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(OwningPlayer))
	{
		if (UEnhancedInputUserSettings* InputSettings = System->GetUserSettings())
		{
			InputSettings->ApplySettings(); // 应用输入设置
		}
	}
}

/**
 * 设置色盲强度
 * @param InColorBlindStrength 色盲强度
 */
void ULyraSettingsShared::SetColorBlindStrength(int32 InColorBlindStrength)
{
	InColorBlindStrength = FMath::Clamp(InColorBlindStrength, 0, 10); // 将色盲强度限制在0-10范围内
	if (ColorBlindStrength != InColorBlindStrength)
	{
		ColorBlindStrength = InColorBlindStrength;
		// 设置Slate渲染器的色觉缺陷类型
		FSlateApplication::Get().GetRenderer()->SetColorVisionDeficiencyType(
			(EColorVisionDeficiency)(int32)ColorBlindMode, (int32)ColorBlindStrength, true, false);
	}
}

/**
 * 获取色盲强度
 * @return 色盲强度
 */
int32 ULyraSettingsShared::GetColorBlindStrength() const
{
	return ColorBlindStrength;
}

/**
 * 设置色盲模式
 * @param InMode 色盲模式
 */
void ULyraSettingsShared::SetColorBlindMode(EColorBlindMode InMode)
{
	if (ColorBlindMode != InMode)
	{
		ColorBlindMode = InMode;
		// 设置Slate渲染器的色觉缺陷类型
		FSlateApplication::Get().GetRenderer()->SetColorVisionDeficiencyType(
			(EColorVisionDeficiency)(int32)ColorBlindMode, (int32)ColorBlindStrength, true, false);
	}
}

/**
 * 获取色盲模式
 * @return 色盲模式
 */
EColorBlindMode ULyraSettingsShared::GetColorBlindMode() const
{
	return ColorBlindMode;
}

/**
 * 应用字幕选项
 */
void ULyraSettingsShared::ApplySubtitleOptions()
{
	if (USubtitleDisplaySubsystem* SubtitleSystem = USubtitleDisplaySubsystem::Get(OwningPlayer))
	{
		FSubtitleFormat SubtitleFormat;
		SubtitleFormat.SubtitleTextSize = SubtitleTextSize; // 字幕文本大小
		SubtitleFormat.SubtitleTextColor = SubtitleTextColor; // 字幕文本颜色
		SubtitleFormat.SubtitleTextBorder = SubtitleTextBorder; // 字幕文本边框
		SubtitleFormat.SubtitleBackgroundOpacity = SubtitleBackgroundOpacity; // 字幕背景不透明度

		SubtitleSystem->SetSubtitleDisplayOptions(SubtitleFormat); // 设置字幕显示选项
	}
}

//////////////////////////////////////////////////////////////////////

/**
 * 设置后台音频允许设置
 * @param NewValue 新的后台音频设置
 */
void ULyraSettingsShared::SetAllowAudioInBackgroundSetting(ELyraAllowBackgroundAudioSetting NewValue)
{
	if (ChangeValueAndDirty(AllowAudioInBackground, NewValue))
	{
		ApplyBackgroundAudioSettings(); // 如果值已更改，则应用后台音频设置
	}
}

/**
 * 应用后台音频设置
 */
void ULyraSettingsShared::ApplyBackgroundAudioSettings()
{
	if (OwningPlayer && OwningPlayer->IsPrimaryPlayer())
	{
		// 设置非焦点时的音量乘数
		FApp::SetUnfocusedVolumeMultiplier((AllowAudioInBackground != ELyraAllowBackgroundAudioSetting::Off) ? 1.0f : 0.0f);
	}
}

//////////////////////////////////////////////////////////////////////

/**
 * 应用文化设置
 */
void ULyraSettingsShared::ApplyCultureSettings()
{
	if (bResetToDefaultCulture)
	{
		// 重置为默认文化
		const FCulturePtr SystemDefaultCulture = FInternationalization::Get().GetDefaultCulture();
		check(SystemDefaultCulture.IsValid());

		const FString CultureToApply = SystemDefaultCulture->GetName();
		if (FInternationalization::Get().SetCurrentCulture(CultureToApply))
		{
			// 清除此字符串
			GConfig->RemoveKey(TEXT("Internationalization"), TEXT("Culture"), GGameUserSettingsIni);
			GConfig->Flush(false, GGameUserSettingsIni);
		}
		bResetToDefaultCulture = false;
	}
	else if (!PendingCulture.IsEmpty())
	{
		// SetCurrentCulture可能触发PendingCulture被清除（如果广播文化更改），因此我们复制一份进行处理
		const FString CultureToApply = PendingCulture;
		if (FInternationalization::Get().SetCurrentCulture(CultureToApply))
		{
			// 注意：这有意保存到用户配置中
			// 我们需要在玩家登录之前和加载屏幕的早期本地化文本
			GConfig->SetString(TEXT("Internationalization"), TEXT("Culture"), *CultureToApply, GGameUserSettingsIni);
			GConfig->Flush(false, GGameUserSettingsIni);
		}
		ClearPendingCulture(); // 清除待处理的文化设置
	}
}

/**
 * 重置文化设置为当前设置
 */
void ULyraSettingsShared::ResetCultureToCurrentSettings()
{
	ClearPendingCulture(); // 清除待处理的文化设置
	bResetToDefaultCulture = false; // 重置默认文化标志
}

/**
 * 获取待处理的文化设置
 * @return 待处理的文化设置字符串
 */
const FString& ULyraSettingsShared::GetPendingCulture() const
{
	return PendingCulture;
}

/**
 * 设置待处理的文化设置
 * @param NewCulture 新的文化设置
 */
void ULyraSettingsShared::SetPendingCulture(const FString& NewCulture)
{
	PendingCulture = NewCulture;
	bResetToDefaultCulture = false; // 重置默认文化标志
	bIsDirty = true; // 标记为脏
}

/**
 * 文化更改回调
 */
void ULyraSettingsShared::OnCultureChanged()
{
	ClearPendingCulture(); // 清除待处理的文化设置
	bResetToDefaultCulture = false; // 重置默认文化标志
}

/**
 * 清除待处理的文化设置
 */
void ULyraSettingsShared::ClearPendingCulture()
{
	PendingCulture.Reset(); // 重置待处理的文化设置
}

/**
 * 检查是否使用默认文化设置
 * @return 如果使用默认文化设置返回true，否则返回false
 */
bool ULyraSettingsShared::IsUsingDefaultCulture() const
{
	FString Culture;
	GConfig->GetString(TEXT("Internationalization"), TEXT("Culture"), Culture, GGameUserSettingsIni);

	return Culture.IsEmpty(); // 如果文化字符串为空，则使用默认文化
}

/**
 * 重置为默认文化设置
 */
void ULyraSettingsShared::ResetToDefaultCulture()
{
	ClearPendingCulture(); // 清除待处理的文化设置
	bResetToDefaultCulture = true; // 设置重置默认文化标志
	bIsDirty = true; // 标记为脏
}

//////////////////////////////////////////////////////////////////////

/**
 * 应用输入灵敏度
 */
void ULyraSettingsShared::ApplyInputSensitivity()
{
	// 目前为空，可能需要在此处应用输入灵敏度设置
}